/*
 * MainFrame.java Created on Feb 16, 2003 11:05:00 AM
 *
 * Copyright (C) 2003 eRocX Software Group - www.erocx.com
 */
package com.erocx.c24;

import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**
 * <p>Title: MainFrame</p>
 * <p>Description: the main frame of calculate 24</p>
 * 
 * @author		<a href="mailto:eroclu@gmail.com">Andy Lu</a>
 * @version   	1.0
 */

public final class MainFrame extends JFrame {
    private String title = ResourceUtil.getString("application.name");
    private String welcome;
    private String userName;
    private int _a, _b, _c, _d;
    private MessagePanel messagePanel;
    private JLabel answerLabel, answerValueLabel;
    private JLabel playCardA, playCardB, playCardC, playCardD;
    private JLabel userLabel, userValueLabel;
    private JLabel operandsLabel, operands;
    private JLabel timeLabel, timeValueLabel;
    //private JLabel scoreLabel, scoreValueLabel;
    private JLabel winLabel, winValueLabel;
    private JLabel lostLabel, lostValueLabel;
    private JLabel totalLabel, totalValueLabel;
    private int win, lost, total;
    private JLabel yourAnswerLabel;
    private JTextField answerTF;
    private ControlButton newButton, continueButton, answerButton, stopButton, exitButton;
    private InputButton zero, one, two, three, four, five, six, seven, eight, nine;
    private InputButton leftBracket, rightBracket;
    private InputButton add, sub, mul, div;
    private JButton okButton, clearButton;

    private AbstractAction newAction, continueAction, answerAction, stopAction;
    private AbstractAction changeUserAction;
    private AbstractAction aboutAction;
    private AbstractAction exitAction;

    private CoreBean coreBean;

    private InputCalculator calStr;

    private TimeCounter calTime;

    private ApplicationModel model;

    public static final int RUNNING = 1;
    public static final int STOP = 0;
    private int stateFlag = -1;

    public MainFrame() {
        userName = getPlayerName();
        model = new ApplicationModel(userName);

        setTitle(title);
        ImageIcon icon = new ImageIcon(ResourceUtil.getImage("math24.gif"));
        setIconImage(icon.getImage());

        doPreliminaryWork();

        setJMenuBar(createMenuBar());

        Container c = getContentPane();
        c.add(createContentPanel());

        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        pack();

        initData();

        // place the windown on the center of the screen.
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        setLocation((d.width-getWidth())/2, (d.height-getHeight())/2);

        setResizable(false);
    }

    private String getPlayerName() {
        String name = null;        
        String message = ResourceUtil.getString("input.message");
        String title = ResourceUtil.getString("application.name");
        name = JOptionPane.showInputDialog(this, message, title, JOptionPane.QUESTION_MESSAGE);
        if (name == null) {
            System.exit(0);
        } else if (name.equals("")) {
            name = ResourceUtil.getString("anonymous.user");
        }
        return name;
    }

    private void doPreliminaryWork() {
        coreBean = new CoreBean();
        calStr = new InputCalculator();
        calTime = new TimeCounter();

        welcome = ResourceUtil.getString("welcome.message");
        newAction = new NewAction();
        continueAction = new ContinueAction();
        answerAction = new AnswerAction();
        stopAction = new StopAction();
        changeUserAction = new ChangeUserAction();
        aboutAction = new AboutAction();
        exitAction = new ExitAction();

        messagePanel = new MessagePanel();
        messagePanel.setPreferredSize(new Dimension(320, 23));
        operandsLabel = new JLabel(ResourceUtil.getString("four.numbers"));
        operands = new JLabel();
        answerLabel = new JLabel(ResourceUtil.getString("answer.is"));
        answerValueLabel = new JLabel();
        yourAnswerLabel = new JLabel(ResourceUtil.getString("your.answer"));
        answerTF = new JTextField();
        answerTF.setPreferredSize(new Dimension(100, 23));

        newButton = new ControlButton(ResourceUtil.getString("new.game"));
        continueButton = new ControlButton(ResourceUtil.getString("continue"));
        answerButton = new ControlButton(ResourceUtil.getString("get.answer"));
        stopButton = new ControlButton(ResourceUtil.getString("stop"));
        exitButton = new ControlButton(ResourceUtil.getString("exit"));

        userLabel = new JLabel(ResourceUtil.getString("user.name"));
        userValueLabel = new JLabel();
        //scoreLabel = new JLabel("Score:");
        //scoreValueLabel = new JLabel();
        winLabel = new JLabel(ResourceUtil.getString("win.count"));
        winValueLabel = new JLabel();
        lostLabel = new JLabel(ResourceUtil.getString("lost.count"));
        lostValueLabel = new JLabel();
        totalLabel = new JLabel(ResourceUtil.getString("total"));
        totalValueLabel = new JLabel();
        timeLabel = new JLabel(ResourceUtil.getString("elapsed.time"));
        timeValueLabel = new JLabel();
        Dimension dim = new Dimension(52, 16);
        //scoreValueLabel.setPreferredSize(dim);
        winValueLabel.setPreferredSize(dim);
        lostValueLabel.setPreferredSize(dim);
        totalValueLabel.setPreferredSize(dim);
        timeValueLabel.setPreferredSize(dim);
        //System.out.println(timeValueLabel.getPreferredSize());

        //init the four play card variables
        playCardA = new JLabel();
        playCardB = new JLabel();
        playCardC = new JLabel();
        playCardD = new JLabel();
        dim = new Dimension(71, 96);
        playCardA.setPreferredSize(dim);
        playCardB.setPreferredSize(dim);
        playCardC.setPreferredSize(dim);
        playCardD.setPreferredSize(dim);
        MouseAdapter cardListener = new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                if (stateFlag == 1) {
                    if (e.getSource().equals(playCardA) || e.getSource().equals(playCardB) ||
                        e.getSource().equals(playCardC) || e.getSource().equals(playCardD)) {
                        MainFrame.this.setCursor(new Cursor(Cursor.HAND_CURSOR));
                    }
                }
            }

            public void mouseExited(MouseEvent e) {
                if (stateFlag == 1) {
                    if (e.getSource().equals(playCardA) || e.getSource().equals(playCardB) ||
                        e.getSource().equals(playCardC) || e.getSource().equals(playCardD)) {
                        MainFrame.this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                    }
                }
            }

            public void mouseClicked(MouseEvent e) {
                if (stateFlag == 1) {
                    if (e.getSource().equals(playCardA)) {
                        answerTF.setText(answerTF.getText() + String.valueOf(_a));
                    }
                    if (e.getSource().equals(playCardB)) {
                        answerTF.setText(answerTF.getText() + String.valueOf(_b));
                    }
                    if (e.getSource().equals(playCardC)) {
                        answerTF.setText(answerTF.getText() + String.valueOf(_c));
                    }
                    if (e.getSource().equals(playCardD)) {
                        answerTF.setText(answerTF.getText() + String.valueOf(_d));
                    }
                }
            }
        };
        playCardA.addMouseListener(cardListener);
        playCardB.addMouseListener(cardListener);
        playCardC.addMouseListener(cardListener);
        playCardD.addMouseListener(cardListener);

        //init all the control buttons
        one = new InputButton("1");
        two = new InputButton("2");
        three = new InputButton("3");
        four = new InputButton("4");
        five = new InputButton("5");
        six = new InputButton("6");
        seven = new InputButton("7");
        eight = new InputButton("8");
        nine = new InputButton("9");
        zero = new InputButton("10");
        leftBracket = new InputButton("(");
        rightBracket = new InputButton(")");
        add = new InputButton("+");
        sub = new InputButton("-");
        mul = new InputButton("*");
        div = new InputButton("/");
        okButton = new JButton("=");
        okButton.setPreferredSize(new Dimension(2*zero.getPreferredSize().width, zero.getPreferredSize().height));
        clearButton = new JButton("C");
        clearButton.setPreferredSize(new Dimension(4*zero.getPreferredSize().width, zero.getPreferredSize().height));

        ActionListener listener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (e.getSource().equals(one) || e.getSource().equals(two) || e.getSource().equals(three)
                    || e.getSource().equals(four) || e.getSource().equals(five) || e.getSource().equals(six)
                    || e.getSource().equals(seven) || e.getSource().equals(eight) || e.getSource().equals(nine)
                    || e.getSource().equals(zero) || e.getSource().equals(leftBracket) || e.getSource().equals(rightBracket)
                    || e.getSource().equals(add) || e.getSource().equals(sub) || e.getSource().equals(mul) || e.getSource().equals(div)) {
                    answerTF.setText(answerTF.getText() + ( (JButton) e.getSource()).getText());
                } else if (e.getSource().equals(okButton)) {
                    try {
                        double result = calStr.calculate(answerTF.getText());
                        update((int) result == 24);
                        answerTF.setText(String.valueOf(result));
                    } catch (Exception ex) {                        
                        String message = ResourceUtil.getString("invalid.input");
                        String title = ResourceUtil.getString("application.name");
                        JOptionPane.showMessageDialog(MainFrame.this, message, title, JOptionPane.ERROR_MESSAGE);
                        answerTF.setText(null);
                    }
                } else if (e.getSource().equals(clearButton)) {
                    answerTF.setText(null);
                    //answerTF.requestFocus();
                }
            }
        };

        //add the listeners to buttons
        newButton.addActionListener(newAction);
        continueButton.addActionListener(continueAction);
        answerButton.addActionListener(answerAction);
        stopButton.addActionListener(stopAction);
        exitButton.addActionListener(exitAction);

        one.addActionListener(listener);
        two.addActionListener(listener);
        three.addActionListener(listener);
        four.addActionListener(listener);
        five.addActionListener(listener);
        six.addActionListener(listener);
        seven.addActionListener(listener);
        eight.addActionListener(listener);
        nine.addActionListener(listener);
        zero.addActionListener(listener);
        leftBracket.addActionListener(listener);
        rightBracket.addActionListener(listener);
        add.addActionListener(listener);
        sub.addActionListener(listener);
        mul.addActionListener(listener);
        div.addActionListener(listener);
        okButton.addActionListener(listener);
        clearButton.addActionListener(listener);
    }

    private JPanel createContentPanel() {
        JPanel content = new JPanel();
        //content.setBackground(Color.black);

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        content.setLayout(gbl);

        gbc.anchor = GridBagConstraints.CENTER;
        gbc.gridy = 0;
        gbc.gridx = 0;
        gbc.insets = new Insets(6, 0, 0, 0);
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        content.add(messagePanel, gbc);

        gbc.gridy++;
        gbc.insets = new Insets(4, 10, 0, 10);
        content.add(getPlayCardPanel(), gbc);

        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridy++;
        gbc.gridx = 0;
        gbc.gridwidth = 1;
        gbc.insets = new Insets(6, 18, 0, 0);
        content.add(yourAnswerLabel, gbc);
        gbc.gridx = 1;
        gbc.insets = new Insets(6, 4, 0, 0);
        content.add(answerTF, gbc);
        gbc.gridx = 2;
        gbc.insets = new Insets(6, 4, 0, 0);
        content.add(okButton, gbc);

        JPanel panel = new JPanel();
        panel.add(getScorePanel());
        panel.add(getInputPanel());
        panel.add(getControlPanel());


        gbc.gridy++;
        gbc.gridx = 0;
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.insets = new Insets(5, 10, 8, 10);
        content.add(panel, gbc);

        return content;
    }

    private JPanel getPlayCardPanel() {
        JPanel play = new JPanel();

        play.add(playCardA);
        play.add(playCardB);
        play.add(playCardC);
        play.add(playCardD);

        return play;
    }

    private JPanel getScorePanel() {
        JPanel score = new JPanel();
        //score.setOpaque(false);
        Border etched = BorderFactory.createEtchedBorder();
        TitledBorder tb = BorderFactory.createTitledBorder(etched, ResourceUtil.getString("your.score"));
        score.setBorder(tb);

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        score.setLayout(gbl);

        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridy = 0;
        gbc.gridx = 0;
        gbc.insets = new Insets(2, 5, 0, 0);
        score.add(userLabel, gbc);
        gbc.gridx = 1;
        gbc.insets = new Insets(2, 3, 0, 3);
        score.add(userValueLabel, gbc);
/*
        gbc.gridy++;
        gbc.gridx = 0;
        score.add(scoreLabel, gbc);
        gbc.gridx = 1;
        score.add(scoreValueLabel, gbc);
*/
        gbc.gridy++;
        gbc.gridx = 0;
        gbc.insets = new Insets(3, 5, 0, 0);
        score.add(winLabel, gbc);
        gbc.gridx = 1;
        gbc.insets = new Insets(3, 3, 0, 3);
        score.add(winValueLabel, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        gbc.insets = new Insets(3, 5, 0, 0);
        score.add(lostLabel, gbc);
        gbc.gridx = 1;
        gbc.insets = new Insets(3, 3, 0, 3);
        score.add(lostValueLabel, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        gbc.insets = new Insets(3, 5, 0, 0);
        score.add(totalLabel, gbc);
        gbc.gridx = 1;
        gbc.insets = new Insets(3, 3, 0, 3);
        score.add(totalValueLabel, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        gbc.insets = new Insets(3, 5, 6, 0);
        score.add(timeLabel, gbc);
        gbc.gridx = 1;
        gbc.insets = new Insets(3, 3, 6, 3);
        score.add(timeValueLabel, gbc);

        return score;
    }

    private JPanel getInputPanel() {
        JPanel input = new JPanel();

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        input.setLayout(gbl);

        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridy = 0;
        gbc.gridx = 0;
        gbc.gridwidth = 4;
        input.add(clearButton, gbc);

        gbc.gridwidth = 1;
        gbc.gridy++;
        gbc.gridx = 0;
        input.add(one, gbc);
        gbc.gridx = 1;
        input.add(two, gbc);
        gbc.gridx = 2;
        input.add(three, gbc);
        gbc.gridx = 3;
        input.add(add, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        input.add(four, gbc);
        gbc.gridx = 1;
        input.add(five, gbc);
        gbc.gridx = 2;
        input.add(six, gbc);
        gbc.gridx = 3;
        input.add(sub, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        input.add(seven, gbc);
        gbc.gridx = 1;
        input.add(eight, gbc);
        gbc.gridx = 2;
        input.add(nine, gbc);
        gbc.gridx = 3;
        input.add(mul, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        input.add(leftBracket, gbc);
        gbc.gridx = 1;
        input.add(zero, gbc);
        gbc.gridx = 2;
        input.add(rightBracket, gbc);
        gbc.gridx = 3;
        input.add(div, gbc);

        return input;
    }

    private JPanel getControlPanel() {
        JPanel control = new JPanel();

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        control.setLayout(gbl);

        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.gridy = 0;
        gbc.gridx = 0;

        gbc.gridy++;
        control.add(newButton, gbc);

        gbc.gridy++;
        control.add(continueButton, gbc);

        gbc.gridy++;
        control.add(answerButton, gbc);

        gbc.gridy++;
        control.add(stopButton, gbc);

        gbc.gridy++;
        control.add(exitButton, gbc);


        return control;
    }

    private void initData() {
        //messageLabel.setText("Welcome to here!:)");

        Icon icon = new ImageIcon(ResourceUtil.getCardImage("0.gif"));
        playCardA.setIcon(icon);
        playCardB.setIcon(icon);
        playCardC.setIcon(icon);
        playCardD.setIcon(icon);

        userValueLabel.setText(model.getUserName());
        //scoreValueLabel.setText(String.valueOf(model.getScore()));
        winValueLabel.setText(String.valueOf(model.getWin()));
        lostValueLabel.setText(String.valueOf(model.getLost()));
        totalValueLabel.setText(String.valueOf(model.getTotal()));
        timeValueLabel.setText(model.getTime());

        setStatus(STOP);
    }

    private JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();

        menuBar.add(createFileMenu());
        menuBar.add(createOptionMenu());
        menuBar.add(createHelpMenu());

        return menuBar;
    }

    private JMenu createFileMenu() {
        JMenu file = new JMenu(ResourceUtil.getString("menu.file"));

        file.add(newAction);
        file.add(continueAction);
        file.add(answerAction);
        file.add(stopAction);

        file.addSeparator();
        file.add(exitAction);

        return file;
    }

    private JMenu createOptionMenu() {
        JMenu option = new JMenu(ResourceUtil.getString("menu.option"));

        option.add(changeUserAction);

        return option;
    }

    private JMenu createHelpMenu() {
        JMenu file = new JMenu(ResourceUtil.getString("menu.help"));

        file.add(aboutAction);

        return file;
    }

    private int[] getOperands() {
        int[] opers = new int[4];
        opers[0] = 1 + (int) (Math.random() * 10);
        opers[1] = 1 + (int) (Math.random() * 10);
        opers[2] = 1 + (int) (Math.random() * 10);
        opers[3] = 1 + (int) (Math.random() * 10);

        coreBean.caculate24(opers[0], opers[1], opers[2], opers[3]);
        if (coreBean.isExistAnswer())
            return opers;
        else
            return getOperands();
    }

    private void generateOperands() {
        int[] opers = getOperands();
        _a = opers[0];
        _b = opers[1];
        _c = opers[2];
        _d = opers[3];

        //answerTF.setDocument(new AnswerDocument(_a, _b, _c, _d));

        String[] images = getPlayCards(_a, _b, _c, _d);
        Icon icon = null;
        icon = new ImageIcon(ResourceUtil.getCardImage(images[0]));
        playCardA.setIcon(icon);
        icon = new ImageIcon(ResourceUtil.getCardImage(images[1]));
        playCardB.setIcon(icon);
        icon = new ImageIcon(ResourceUtil.getCardImage(images[2]));
        playCardC.setIcon(icon);
        icon = new ImageIcon(ResourceUtil.getCardImage(images[3]));
        playCardD.setIcon(icon);
    }

    private String[] getPlayCards(int a, int b, int c, int d) {
        String[] images = new String[4];

        class CardData {
            private int value;
            private boolean[] category;
            Random random;

            public CardData(int v) {
                value = v;
                category = new boolean[]{true, true, true, true};
                random = new Random();
            }

            public int getValue() {
                return value;
            }

            public int getRandomAvailableCard() {
                int size = 0;
                for (int i = 0; i < category.length; i++) {
                    if (category[i])
                        size ++;
                }
                int[] avail = new int[size];
                int k = 0;
                for (int i = 0; i < category.length; i++) {
                    if (category[i]) {
                        avail[k] = i;
                        k ++;
                    }
                }
                if (size == 0)
                    return -1;

                int index = random.nextInt(size);
                category[avail[index]] = false;  //set this card used
                return avail[index];
            }
        }

        String path = "";
        String category = null;

        CardData aCard;
        CardData bCard;
        CardData cCard;
        CardData dCard;

        aCard = new CardData(a);
        category = String.valueOf(aCard.getRandomAvailableCard());
        images[0] = path + category + "-" + String.valueOf(a) + ".gif";
        if (b == a) {
            bCard = aCard;
        } else {
            bCard = new CardData(b);
        }
        category = String.valueOf(bCard.getRandomAvailableCard());
        images[1] = path + category + "-" + String.valueOf(b) + ".gif";
        if (c == a) {
            cCard = aCard;
        } else if (c == b) {
            cCard = bCard;
        } else {
            cCard = new CardData(c);
        }
        category = String.valueOf(cCard.getRandomAvailableCard());
        images[2] = path + category + "-" + String.valueOf(c) + ".gif";
        if (d == a) {
            dCard = aCard;
        } else if (d == b) {
            dCard = bCard;
        } else if (d == c) {
            dCard = cCard;
        } else {
            dCard = new CardData(d);
        }
        category = String.valueOf(dCard.getRandomAvailableCard());
        images[3] = path + category + "-" + String.valueOf(d) + ".gif";

        return images;
    }

    private void setStatus(int state) {
        stateFlag = state;
        switch (state) {
            case STOP:
                messagePanel.setMessage(welcome);

                Icon icon = new ImageIcon(ResourceUtil.getCardImage("0.gif"));
                playCardA.setIcon(icon);
                playCardB.setIcon(icon);
                playCardC.setIcon(icon);
                playCardD.setIcon(icon);

                answerTF.setEnabled(false);

                continueAction.setEnabled(false);
                answerAction.setEnabled(false);
                stopAction.setEnabled(false);
                continueButton.setEnabled(false);
                answerButton.setEnabled(false);
                stopButton.setEnabled(false);

                //set control buttons status
                one.setEnabled(false);
                two.setEnabled(false);
                three.setEnabled(false);
                four.setEnabled(false);
                five.setEnabled(false);
                six.setEnabled(false);
                seven.setEnabled(false);
                eight.setEnabled(false);
                nine.setEnabled(false);
                zero.setEnabled(false);
                leftBracket.setEnabled(false);
                rightBracket.setEnabled(false);
                add.setEnabled(false);
                sub.setEnabled(false);
                mul.setEnabled(false);
                div.setEnabled(false);
                okButton.setEnabled(false);
                clearButton.setEnabled(false);

                break;
            case RUNNING:
                messagePanel.setMessage(welcome);

                answerTF.setEnabled(true);

                continueAction.setEnabled(true);
                answerAction.setEnabled(true);
                stopAction.setEnabled(true);
                continueButton.setEnabled(true);
                answerButton.setEnabled(true);
                stopButton.setEnabled(true);

                //the control buttons status
                one.setEnabled(inOperands(Integer.parseInt(one.getText())));
                two.setEnabled(inOperands(Integer.parseInt(two.getText())));
                three.setEnabled(inOperands(Integer.parseInt(three.getText())));
                four.setEnabled(inOperands(Integer.parseInt(four.getText())));
                five.setEnabled(inOperands(Integer.parseInt(five.getText())));
                six.setEnabled(inOperands(Integer.parseInt(six.getText())));
                seven.setEnabled(inOperands(Integer.parseInt(seven.getText())));
                eight.setEnabled(inOperands(Integer.parseInt(eight.getText())));
                nine.setEnabled(inOperands(Integer.parseInt(nine.getText())));
                zero.setEnabled(inOperands(Integer.parseInt(zero.getText())));
                leftBracket.setEnabled(true);
                rightBracket.setEnabled(true);
                add.setEnabled(true);
                sub.setEnabled(true);
                mul.setEnabled(true);
                div.setEnabled(true);
                okButton.setEnabled(true);
                clearButton.setEnabled(true);

                break;
            default:
                return;
        }
    }

    private boolean inOperands(int i) {
        if (i == _a || i == _b || i == _c || i == _d)
            return true;

        return false;
    }

    private void update(boolean result) {
        model.update(result);
        winValueLabel.setText(String.valueOf(model.getWin()));
        lostValueLabel.setText(String.valueOf(model.getLost()));
        totalValueLabel.setText(String.valueOf(model.getTotal()));

    }

    private boolean checkAnswer(String answer) {
        return true;
    }

    class AnswerDocument extends PlainDocument {
        private String[] operandsChars;
        private String[] operatorsChars;

        public AnswerDocument(int a, int b, int c, int d) {
            operandsChars = new String[]{String.valueOf(a), String.valueOf(b), String.valueOf(c), String.valueOf(d)};
            operatorsChars = new String[]{"(", ")", "+", "-", "*", "/"};
        }
        public void insertString(int offset, String str, AttributeSet a)
                  throws BadLocationException {
            String valid = parseInput(str);

            super.insertString(offset, valid, a);
        }

        private String parseInput(String str) {
            if (str == null)
                return null;

            String valid = "";
            for (int i = 0; i < str.length(); i ++) {
                String c = String.valueOf(str.charAt(i));
                if (isValidate(c))
                    valid = valid + c;
            }

            return valid;
        }

        private boolean isValidate(String str) {
            for (int i = 0; i < operandsChars.length; i ++) {
                String c = operandsChars[i];
                if (str.equals(c))
                    return true;
            }

            for (int i = 0; i < operatorsChars.length; i ++) {
                String c = operatorsChars[i];
                if (str.equals(c))
                    return true;
            }

            return false;
        }

    }

    class NewAction extends AbstractAction {
        public NewAction() {
            super(ResourceUtil.getString("new.game"));
        }

        public void actionPerformed(ActionEvent e) {
            model = new ApplicationModel(userName);
            generateOperands();
            winValueLabel.setText(String.valueOf(model.getWin()));
            lostValueLabel.setText(String.valueOf(model.getLost()));
            totalValueLabel.setText(String.valueOf(model.getTotal()));
            calTime.stop();
            calTime.clear();
            calTime.start();
            int delay = 1000; //milliseconds
            ActionListener taskPerformer = new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    timeValueLabel.setText(calTime.getTime());
                }
            };
            new Timer(delay, taskPerformer).start();
            setStatus(RUNNING);
        }
    }

    class ContinueAction extends AbstractAction {
        public ContinueAction() {
            super(ResourceUtil.getString("continue"));
        }

        public void actionPerformed(ActionEvent e) {
            try {
                double result = calStr.calculate(answerTF.getText());
                update((int) result == 24);
            } catch (Exception ex) {
                update(false);
            }
            generateOperands();
            //operands.setText(String.valueOf(_a)+String.valueOf(_b)+String.valueOf(_c)+String.valueOf(_d));
            answerTF.setText(null);
            setStatus(RUNNING);
        }
    }

    class AnswerAction extends AbstractAction {
        public AnswerAction() {
            super(ResourceUtil.getString("get.answer"));
        }

        public void actionPerformed(ActionEvent e) {
            coreBean.caculate24(_a, _b, _c, _d);
            messagePanel.setMessage(ResourceUtil.getString("answer.is.label") + coreBean.getAAnswer());
            answerTF.setText(coreBean.getAAnswer());
        }
    }

    class StopAction extends AbstractAction {
        public StopAction() {
            super(ResourceUtil.getString("stop"));
        }

        public void actionPerformed(ActionEvent e) {
            calTime.stop();
            timeValueLabel.setText(calTime.getTime());
            model.setTime(calTime.getTime());
            setStatus(STOP);
        }
    }

    class ChangeUserAction extends AbstractAction {
        public ChangeUserAction() {
            super(ResourceUtil.getString("menu.file.changeuser"));
        }

        public void actionPerformed(ActionEvent e) {
            String name = null;            
            String message = ResourceUtil.getString("input.message");
            String title = ResourceUtil.getString("application.name");
            name = JOptionPane.showInputDialog(MainFrame.this, message, title, JOptionPane.QUESTION_MESSAGE);
            if (name != null) {
                if (name.equals("")) {
                    name = ResourceUtil.getString("anonymous.user");
                }
                userName = name;
                userValueLabel.setText(userName);
            }
        }
    }

    class ExitAction extends AbstractAction {
        public ExitAction() {
            super(ResourceUtil.getString("exit"));
        }

        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    }

    class AboutAction extends AbstractAction {
        public AboutAction() {
            super(ResourceUtil.getString("menu.help.about"));
        }

        public void actionPerformed(ActionEvent e) {
            AboutDialog aboutDialog = new AboutDialog(MainFrame.this);
            aboutDialog.show();
        }
    }

    class MessagePanel extends JPanel {
        private String message;
        private JLabel messageLabel;

        public MessagePanel() {
            super();
            messageLabel = new JLabel(welcome);
            add(messageLabel);
        }

        public void setMessage(String msg) {
            message = msg;
            messageLabel.setText(message);
        }
    }

    class InputButton extends JButton {
        public InputButton(String text) {
            super(text);
            setPreferredSize(new Dimension(25, 25));
            setMargin(new Insets(0, 0, 0, 0));
        }
    }

    class ControlButton extends JButton {
        public ControlButton(String text) {
            super(text);
            setPreferredSize(new Dimension(85, 25));
            setMargin(new Insets(0, 0, 0, 0));
        }
    }

    public static void main(String[] args) {
        MainFrame frame = new MainFrame();
        frame.setVisible(true);
        //System.out.println(frame.getPreferredSize());
    }
}